﻿#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "langhelp.h"
#include <QFileDialog>
#include <QFile>
#include <QFileInfo>
#include <QDesktopServices>
#include <QMessageBox>

#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , m_stop(false)
    , m_codeLines(0)
    , m_commentLines(0)
    , m_spaceLines(0)
    , m_sumLines(0)
    , m_fileSum(0)
    , m_fileSize(0)
    , m_fileTypeSum(0)
    , m_c(true)
    , m_cxx(true)
    , m_python(false)
    , m_r(false)
    , m_mysql(false)
    , m_sqlServer(false)
    , m_oracle(false)
    , m_matlab(false)
{
    ui->setupUi(this);

    ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);
    ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
    ui->tableWidget->setSelectionBehavior(QTableWidget::SelectRows);
    ui->tableWidget->setAlternatingRowColors(true);
    int w = ui->tableWidget->columnWidth(2);
    ui->tableWidget->setColumnWidth(2, w + 20);

    m_rightMenu.addAction(ui->actionFilePos);
    m_rightMenu.addSeparator();
    m_rightMenu.addAction(ui->actionDelete);
    m_rightMenu.addAction(ui->actionClean);
    m_rightMenu.addAction(ui->actionDeleteType);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::setTableData(int row, const QString &name, const QString &type, int size)
{
    // 文件名称
    QTableWidgetItem *item = ui->tableWidget->item(row, 0);
    if(Q_NULLPTR == item)
    {
        item = new QTableWidgetItem;
        ui->tableWidget->setItem(row, 0, item);
    }
    item->setText(name);

    // 文件类型
    item = ui->tableWidget->item(row, 1);
    if(Q_NULLPTR == item)
    {
        item = new QTableWidgetItem;
        ui->tableWidget->setItem(row, 1, item);
    }
    item->setText(type);

    // 文件大小
    item = ui->tableWidget->item(row, 2);
    if(Q_NULLPTR == item)
    {
        item = new QTableWidgetItem;
        ui->tableWidget->setItem(row, 2, item);
    }
    item->setText(QString::number(size));

    // 代码行数
    item = ui->tableWidget->item(row, 3);
    if(Q_NULLPTR == item)
    {
        item = new QTableWidgetItem;
        ui->tableWidget->setItem(row, 3, item);
    }
    item->setText("...");
}

QStringList MainWindow::getFiles(const QString &dir, const QStringList &filter)
{
    QDir dirs(dir);
    dirs.setFilter(QDir::NoDotAndDotDot | QDir::Files);
    QStringList files = dirs.entryList(filter);
    for(int i = 0; i < files.size(); i++)
        files.replace(i, dir + "/" + files.at(i));
    dirs.setFilter(QDir::NoDotAndDotDot | QDir::AllDirs);
    QStringList names = dirs.entryList();
    for(auto f : names)
    {
        QString d = dir + "/" + f;
        files.append(getFiles(d, filter));
    }
    return files;
}

void MainWindow::parseFileInfo(const QStringList &files)
{
    int index = ui->tableWidget->rowCount();
    int count = index + files.size();
    ui->tableWidget->setRowCount(count);
    for(auto f : files)
    {
        QFileInfo info(f);
        QString name = info.absoluteFilePath();
        QString type = "." + info.suffix();
        double size = info.size() / 1024. + 0.5;
        setTableData(index, name, type, qRound(size));
        ++index;
    }
    m_files.append(files);
}




void MainWindow::on_btnDir_clicked()
{
    Qt::CheckState state = ui->checkBoxSubDir->checkState();
    QString str = ui->lineEditType->text();
    QStringList filter;
    filter = str.split(",");
    for(int i = filter.size() - 1; i >= 0; i--)
    {
        QString tmp = filter.at(i);
        if(tmp.isEmpty())
            filter.removeAt(i);
    }

    QString path = QFileDialog::getExistingDirectory(this, "选择文件夹");
    if(path.isEmpty())
        return;
    QStringList files;
    if(Qt::Unchecked == state)
    {
        QDir dir(path);
        dir.setFilter(QDir::NoDotAndDotDot | QDir::Files);
        QStringList fs = dir.entryList(filter);
        for(auto d : fs)
            files.append(path + "/" + d);
    }
    else
    {
        files = getFiles(path, filter);
    }

    parseFileInfo(files);
}

void MainWindow::on_btnFile_clicked()
{
    QStringList files = QFileDialog::getOpenFileNames(this, "选择文件");

    parseFileInfo(files);
}

void MainWindow::on_btnStart_clicked()
{
    m_stop = true;
    m_codeLines = 0;
    m_commentLines = 0;
    m_spaceLines = 0;
    m_sumLines = 0;
    m_fileSum = 0;
    m_fileSize = 0;
    m_fileTypeSum = 0;

    ui->lineEditCodeLine->setText("");
    ui->lineEditCommentLine->setText("");
    ui->lineEditSpaceLine->setText("");
    ui->lineEditSumLine->setText("");
    ui->lineEditFile->setText("");
    ui->lineEditSumFileSize->setText("");
    ui->lineEditTypeSumNum->setText("");

    QStringList typeList;
    int count = ui->tableWidget->rowCount();
    for(int i = 0; i < count; i++)
    {
        if(!m_stop)
            break;

        QTableWidgetSelectionRange range(i, 0, i, 3);
        ui->tableWidget->setRangeSelected(range, true);
        QTableWidgetItem *item = ui->tableWidget->item(i, 0);
        ui->tableWidget->scrollToItem(item);

        ui->tableWidget->item(i, 3)->setText("正在计算...");
        QString fileName = ui->tableWidget->item(i, 0)->text();

        QFileInfo info(fileName);
        QString name = info.absoluteFilePath();
        QString type = info.suffix();
        double size = info.size() / 1024.;

        ++m_fileSum;
        m_fileSize += size;
        if(!typeList.contains(type))
            typeList.append(type);

        QFile f(fileName);
        if(!f.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            ui->tableWidget->item(i, 3)->setText("无法打开文件，忽略计算");
            continue;
        }
        int lineCount = 0, feedComment = 0;
        bool feed = false;
        while (!f.atEnd())
        {
            QString line = f.readLine();
            ++lineCount;
            line.replace(' ', "");
            line.replace('\n', "");
            if(line.isEmpty())
                ++m_spaceLines;

            //  1. 以 // 开头的注释
            //  2. 以 /* 开头且以 */ 结束的注释
            if(line.startsWith("//") || (line.startsWith("/*") && line.endsWith("*/")))
                ++m_commentLines;
            // 3. 以 /* 开头但换行
            if(line.startsWith("/*") && !line.endsWith("*/"))
                feed = true;
            if(feed)
                ++feedComment;
            if(!line.startsWith("/*") && line.endsWith("*/"))
                feed = false;
            // 3. 以 <!--注释内容--> 注释，可换行
            if(line.startsWith("<!--") && line.endsWith("-->"))
                ++m_commentLines;
            if(line.startsWith("<!--") && !line.endsWith("-->"))
                feed = true;
            if(feed)
                ++feedComment;
            if(!line.startsWith("<!--") && line.endsWith("-->"))
                feed = false;

            // python
            if(m_python)
            {
                if(line.startsWith("#"))
                    ++m_commentLines;

                if(line.startsWith("'''") && line.endsWith("'''"))
                    ++m_commentLines;
                if(line.startsWith("'''") && !line.endsWith("'''"))
                    feed = true;
                if(feed)
                    ++feedComment;
                if(!line.startsWith("'''") && line.endsWith("'''"))
                    feed = false;

                if(line.startsWith(""""") && line.endsWith("""""))
                    ++m_commentLines;
                if(line.startsWith(""""") && !line.endsWith("""""))
                    feed = true;
                if(feed)
                    ++feedComment;
                if(!line.startsWith(""""") && line.endsWith("""""))
                    feed = false;
            }

            // R
            if(m_r)
            {
                if(line.startsWith("#"))
                    ++m_commentLines;

                if(line.startsWith("if(false){") && line.endsWith("}"))
                    ++m_commentLines;
                if(line.startsWith("if(false){") && !line.endsWith("}"))
                    feed = true;
                if(feed)
                    ++feedComment;
                if(!line.startsWith("if(false){") && line.endsWith("}"))
                    feed = false;
            }

            // MySQL
            if(m_mysql)
            {
                if(line.startsWith("#"))
                    ++m_commentLines;

                if(line.startsWith("--"))
                    ++m_commentLines;
            }

            // SQL Server
            if(m_sqlServer)
            {
                if(line.startsWith("--"))
                    ++m_commentLines;
            }

            // matlab
            if(m_sqlServer)
            {
                if(line.startsWith("#"))
                    ++m_commentLines;

                if(line.startsWith("%%") && line.endsWith("%%"))
                    ++m_commentLines;
                if(line.startsWith("%%") && !line.endsWith("%%"))
                    feed = true;
                if(feed)
                    ++feedComment;
                if(!line.startsWith("%%") && line.endsWith("%%"))
                    feed = false;

                if(line.startsWith("%{") && line.endsWith("%}"))
                    ++m_commentLines;
                if(line.startsWith("%{") && !line.endsWith("%}"))
                    feed = true;
                if(feed)
                    ++feedComment;
                if(!line.startsWith("%{") && line.endsWith("%}"))
                    feed = false;
            }
        }
        m_commentLines += feedComment;
        m_sumLines += lineCount;
        f.close();

        ui->tableWidget->item(i, 3)->setText(QString::number(lineCount));

        QApplication::processEvents();
    }

    m_codeLines = m_sumLines - m_spaceLines - m_commentLines;
    ui->lineEditCodeLine->setText(QString::number(m_codeLines));
    ui->lineEditCommentLine->setText(QString::number(m_commentLines));
    ui->lineEditSpaceLine->setText(QString::number(m_spaceLines));
    ui->lineEditSumLine->setText(QString::number(m_sumLines));
    ui->lineEditFile->setText(QString::number(m_fileSum));
    ui->lineEditSumFileSize->setText(QString::number(qRound(m_fileSize)));
    m_fileTypeSum = typeList.size();
    ui->lineEditTypeSumNum->setText(QString::number(m_fileTypeSum));
}

void MainWindow::on_btnStop_clicked()
{
    m_stop = false;
}

void MainWindow::on_tableWidget_customContextMenuRequested(const QPoint &)
{
    m_rightMenu.exec(QCursor::pos());
}

void MainWindow::on_actionDelete_triggered()
{
    QList<QTableWidgetSelectionRange> range = ui->tableWidget->selectedRanges();
    for(auto r : range)
    {
        int srow = r.topRow();
        int erow = r.bottomRow();
        for(int i = erow; i >= srow; i--)
        {
            ui->tableWidget->removeRow(i);
            m_files.removeAt(i);
        }
    }
}

void MainWindow::on_actionClean_triggered()
{
    ui->tableWidget->setRowCount(0);
    m_files.clear();

    ui->lineEditCodeLine->setText("");
    ui->lineEditCommentLine->setText("");
    ui->lineEditSpaceLine->setText("");
    ui->lineEditSumLine->setText("");
    ui->lineEditFile->setText("");
    ui->lineEditSumFileSize->setText("");
    ui->lineEditTypeSumNum->setText("");
}

void MainWindow::on_actionDeleteType_triggered()
{
    int row = ui->tableWidget->currentRow();
    QString str = ui->tableWidget->item(row, 1)->text();

    int count = ui->tableWidget->rowCount();
    for(int i = count - 1; i >= 0; i--)
    {
        QString type = ui->tableWidget->item(i, 1)->text();
        if(str == type)
        {
            ui->tableWidget->removeRow(i);
            m_files.removeAt(i);
        }
    }
}

void MainWindow::on_actionFilePos_triggered()
{
    int row = ui->tableWidget->currentRow();
    QString str = ui->tableWidget->item(row, 0)->text();
    QString dir = str.left(str.lastIndexOf('/'));

    QDesktopServices::openUrl(QUrl(dir.toLocal8Bit()));
}

void MainWindow::on_actionCommentHelp_triggered()
{
    LangHelp dlg(this);
    dlg.exec();
}

void MainWindow::on_actionPython_triggered()
{
    if(m_c || m_cxx)
        if(QMessageBox::No == QMessageBox::question(this, "警告", "python 注释与 C/C++ 头文件引用冲突，是否确定继续？"))
            return;

    m_python = ui->actionPython->isChecked();
}

void MainWindow::on_actionC_triggered()
{
    m_c = ui->actionC->isChecked();
}

void MainWindow::on_actionCXX_triggered()
{
    m_cxx = ui->actionCXX->isChecked();
}

void MainWindow::on_actionR_triggered()
{
    m_r = ui->actionR->isChecked();
}

void MainWindow::on_actionMySQL_triggered()
{
    m_mysql = ui->actionMySQL->isChecked();
}

void MainWindow::on_actionSQL_Server_triggered()
{
    m_sqlServer = ui->actionSQL_Server->isChecked();
}

void MainWindow::on_actionOracle_PLSQL_triggered()
{
    m_oracle = ui->actionOracle_PLSQL->isChecked();
}

void MainWindow::on_actionMatlab_triggered()
{
    m_matlab = ui->actionMatlab->isChecked();
}
